package org.zjt.vertx.demo;

import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.Json;
import io.vertx.ext.web.FileUpload;
import io.vertx.ext.web.Route;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;
import lombok.extern.slf4j.Slf4j;
import org.zjt.vertx.demo.domain.User;

import java.util.Objects;
import java.util.Set;

/**
 * @author juntao.zhang
 * @version V1.0
 * @Description: TODO
 * @Package org.zjt.vertx.demo
 * @date 2018/6/10 10:52
 */
@Slf4j
public class HttpRouter {

    /**
     * 多个相同的router顺序执行:  route1 -> route2 -> route3
     * @param router
     */
    public static void multiRouter(Router router) {

        Route route1 = router.route("/some/path/").handler(routingContext -> {

            HttpServerResponse response = routingContext.response();
            // enable chunked responses because we will be adding data as
            // we execute over other handlers. This is only required once and
            // only if several handlers do output.
            response.setChunked(true);

            response.write("route1\n");

            log.info(Thread.currentThread().getName());
            //定时器5秒后调用下一个router2  Call the next matching route after a 5 second delay
            routingContext.vertx().setTimer(5000, tid -> routingContext.next());

            log.info("--------------------route1----------------------");

        });

        Route route2 = router.route("/some/path/").handler(routingContext -> {

            HttpServerResponse response = routingContext.response();
            response.write("route2\n");

            log.info("-------------------route2-----------------------");
            log.info(Thread.currentThread().getName());
            // Call the next matching route after a 5 second delay
            routingContext.vertx().setTimer(5000, tid -> routingContext.next());
        });

        Route route3 = router.route("/some/path/").handler(routingContext -> {

            HttpServerResponse response = routingContext.response();
            response.write("route3");
            log.info(Thread.currentThread().getName());
            log.info("---------------------route3---------------------");

            // Now end the response
            routingContext.response().end();
        });
    }


    /**
     * 单个路由器模式
     * @param router
     */
    public static void singleRouter(Router router) {
        router.get("/hello").handler(routingContext -> {

            Buffer body = routingContext.getBody();
            if (Objects.nonNull(body))
                log.info(body.getString(0,body.length()));

            log.info(String.valueOf(routingContext.queryParam("name")));

            // This handler will be called for every request
            HttpServerResponse response = routingContext.response();
            response.putHeader("content-type", "text/plain");
            log.info(Thread.currentThread().getName());
            // Write to the response and end it
            response.end("Hello World from Vert.x-Web!");
        });
    }


    /**
     * 阻塞处理程序看起来就像一个正常的处理程序，但它由Vert.x使用来自工作池的线程不使用事件循环来调用。
     *
     * 用户 调用传统的阻塞API或进行一些密集计算。
     *
     * @param router
     */
    public static void blockingHandler(Router router){
        router.get("/blocking").blockingHandler(routingContext -> {

            // Do something that might take some time synchronously
            doSomethingThatBlocks();

            log.info(Thread.currentThread().getName());

            // Now call the next handler
            routingContext.next();
        }).blockingHandler(routingContext ->{

            log.info(Thread.currentThread().getName());

            // Now call the next handler
            routingContext.next();
        });
    }


    /**
     * 精准路由
     *
     * @param router
     */
    public static void exactRouter(Router router) {
        router.route().path("/some/path/1/").handler(routingContext ->{
            HttpServerResponse response = routingContext.response();
            response.end("exactRouter zhangsajun");
        });
    }


    /**
     * 匹配路由
     * @param router
     */
    public static void patternRouter(Router router) {
        router.route().path("/some/path/*").handler(routingContext ->{
            HttpServerResponse response = routingContext.response();
            response.end("patternRouter  zhangsajun");
        });
    }

    /**
     *  POST 的 rest URL param
     * @param router
     */
    public static void POSTRouter(Router router) {
         router.route(HttpMethod.POST, "/catalogue/products/:producttype/:productid/").handler(routingContext -> {

            String productType = routingContext.request().getParam("producttype");
            String productID = routingContext.request().getParam("productid");

            // Do something with them...
             routingContext.response().end(productType + productID);
        });


        /**
         * 通配符匹配
         */
        router.getWithRegex(".*foo").handler(routingContext -> {

            log.info(routingContext.request().uri());
            // Will be called for any GET request to a path
            // ending with `foo`

        });
    }


    /**
     * 多http方法路由  兼容 post 和put
     * @param router
     */
    public static void multiMethodRouter(Router router) {
        router.route().method(HttpMethod.POST).method(HttpMethod.PUT).handler(routingContext -> {

            // This handler will be called for any POST or PUT request

            HttpServerRequest request = routingContext.request();
            log.info("url:{}\tmethod:{}",request.uri() , request.method());

            HttpServerResponse response = routingContext.response();
            response.end("Hello World from Vert.x-Web!");
        });
    }

    /**
     * 根据media type来匹配路由。
     * curl -H "Content-Type:application/json" http://localhost:8080/myapi/orders
     * @param router
     */
    public static void mediaTypeRouter(Router router) {
        router.route(HttpMethod.GET, "/myapi/orders").consumes("application/json").produces("application/json")
            .handler(routingContext -> {
                User zhangsan = User.builder().age(23).name("zhangsan").build();
                routingContext.response().end(Json.encode(zhangsan));
            });
    }


    /**
     *  next 到下一个router中 ，并通过routingContext 传递参数
     * @param router
     */
    public static void multiNextRouter(Router router) {
        router.get("/some/next/*").handler(routingContext -> {

            routingContext.put("foo", "bar");
            routingContext.next();

        });

        router.get("/some/next/*").handler(routingContext -> {

            routingContext.put("name", "zhangsan");
            routingContext.next();

        });

        router.get("/some/next/other").handler(routingContext -> {

            String bar = routingContext.get("foo");
            String name = routingContext.get("name");

            log.info(bar +"    "+ name);

            // Do something with bar
            routingContext.response().end(bar +"    "+ name);

        });
    }


    /**\
     * 文件处理
     * @param router
     */
    public static void FileUploadRouter(Router router) {

        router.route().handler(BodyHandler.create());

        router.post("/some/path/uploads").handler(routingContext -> {

            Set<FileUpload> uploads = routingContext.fileUploads();
            // Do something with uploads....

        });

    }

    public static void doSomethingThatBlocks() {

        log.info(Thread.currentThread().getName());
    }
}
